package osmedile.intellij.checkmyvars;

import static osmedile.intellij.checkmyvars.VarChecker.*;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Olivier Smedile
 * @version $Id: ConfigImpl.java 52 2008-07-29 10:32:50Z osmedile $
 */
public class ConfigImpl implements IConfig, Serializable {
    private List<VarChecker> varCheckers;

    private boolean askToCreateSample;

    // --------------------------- CONSTRUCTORS ---------------------------

    public ConfigImpl() {
        this.varCheckers = new ArrayList<VarChecker>();

        resetToDefault();
    }

    public void addHibernateLikeDefaultConfig() {
        varCheckers.add(new VarChecker("@Length", "string",
                "if($VAR$.length() <= $A_Length_P_min$ ||$VAR$.length() => $A_Length_P_max$) {\n" +
                        "throw new IllegalArgumentException(\"$VAR$ length must be between " +
                        "$A_Length_P_min$ and $A_Length_P_max$ (inclusive)\");\n" +
                        "}",
                HIBERNATE_GRP, false));

        varCheckers.add(new VarChecker("@Range", "number",
                "if($VAR$ < $A_Range_P_min$ ||$VAR$ > $A_Range_P_max$) {\n" +
                        "throw new IllegalArgumentException(\"$VAR$ value must be between " +
                        "$A_Range_P_min$ and $A_Range_P_max$ (inclusive)\");\n" +
                        "}  ",
                HIBERNATE_GRP, false));

        varCheckers.add(new VarChecker("@Range", "number",
                "if($VAR$ < $A_Range_P_min$ ||$VAR$ > $A_Range_P_max$) {\n" +
                        "throw new IllegalArgumentException(\"$VAR$ value must be between " +
                        "$A_Range_P_min$ and $A_Range_P_max$ (inclusive)\");\n" +
                        "}  ",
                HIBERNATE_GRP, false));

        varCheckers.add(new VarChecker("@Range", "string",
                "Number n;\n" +
                        "try {\n" +
                        "   n = NumberFormat.getNumberInstance().parse(s);\n" +
                        "   if(n.doubleValue() < $A_Range_P_min$ || n.doubleValue() > $A_Range_P_max$) {\n" +
                        "       throw new IllegalArgumentException(\"$VAR$ size must be between $A_Range_P_min$ and $A_Range_P_max$ (inclusive)\");  \n" +
                        "   }\n" +
                        "} catch (ParseException e) {\n" +
                        "   throw new IllegalArgumentException(\"$VAR$ must be numeric\", e);\n" +
                        "}",
                HIBERNATE_GRP, false));

        varCheckers.add(new VarChecker("@Size", "collection; array; varags; map",
                "if($VAR$.length() <= $A_Size_P_min$ ||$VAR$.size() => $A_Size_P_max$) {\n" +
                        "throw new IllegalArgumentException(\"$VAR$ size must be between " +
                        "$A_Size_P_min$ and $A_Size_P_max$ (inclusive)\");\n" +
                        "}",
                HIBERNATE_GRP, false));

        varCheckers.add(new VarChecker("@Past", "date",
                "if (!$VAR$.before( new Date()) {\n" +
                        "throw new IllegalArgumentException(\"$VAR$ must be in the past\");\n" +
                        "}",
                HIBERNATE_GRP, false));


        varCheckers.add(new VarChecker("@Past", "calendar",
                "if (!$VAR$.before( Calendar.getInstance()) {\n" +
                        "throw new IllegalArgumentException(\"$VAR$ must be in the past\");\n" +
                        "}",
                HIBERNATE_GRP, false));

        varCheckers.add(new VarChecker("@Future", "date",
                "if (!$VAR$.after( new Date()) {\n" +
                        "throw new IllegalArgumentException(\"$VAR$ must be in the future\");\n" +
                        "}",
                HIBERNATE_GRP, false));


        varCheckers.add(new VarChecker("@Future", "calendar",
                "if (!$VAR$.after( Calendar.getInstance()) {\n" +
                        "throw new IllegalArgumentException(\"$VAR$ must be in the future\");\n" +
                        "}",
                HIBERNATE_GRP, false));

    }

    public void addJdk14DefaultConfig() {
        varCheckers.add(new VarChecker("@Default", "collection",
                "if($VAR$ == null) {\n" +
                        "    $VAR$ = Collections.EMPTY_LIST;\n" +
                        "}", JDK14_GRP, false));

        varCheckers.add(new VarChecker("@Default", "map",
                "if($VAR$ == null) {\n" +
                        "    $VAR$ = Collections.EMPTY_MAP;\n" +
                        "}", JDK14_GRP, false));

        varCheckers.add(new VarChecker("@Default", "array; varags",
                "if($VAR$ == null) {\n" +
                        "    $VAR$ = new $VAR_TYPE$[0];\n" +
                        "}", JDK14_GRP, false));
    }

    public void resetToDefault() {
        askToCreateSample = true;

        varCheckers.add(new VarChecker("@NotNull", null,
                "if($VAR$ == null) {\n" +
                        "    throw new IllegalArgumentException(\"$VAR$ must not be null\");\n" +
                        "}"));

        //Not Empty
        varCheckers.add(new VarChecker("@NotEmpty", "string",
                "if($VAR$ == null || $VAR$.length() == 0) {\n" +
                        "    throw new IllegalArgumentException(\"$VAR$ must not be empty\");\n" +
                        "}"));

        varCheckers.add(new VarChecker("@NotEmpty", "collection; map",
                "if($VAR$ == null || $VAR$.size() == 0) {\n" +
                        "    throw new IllegalArgumentException(\"$VAR$ must not be empty\");\n" +
                        "}"));

        varCheckers.add(new VarChecker("@NotEmpty", "array; varags",
                "if($VAR$ == null || $VAR$.length == 0) {\n" +
                        "    throw new IllegalArgumentException(\"$VAR$ must not be empty\");\n" +
                        "}"));


        varCheckers.add(new VarChecker("@NotBlank", "string",
                "if($VAR$ == null || $VAR$.trim().length()  == 0) {\n" +
                        "    throw new IllegalArgumentException(\"$VAR$ must not be blank\");\n" +
                        "}"));

        //default
        varCheckers.add(new VarChecker("@Default", "string",
                "if($VAR$ == null) {\n" +
                        "    $VAR$ = $A_Default_P_value$;\n" +
                        "}"));

        varCheckers.add(new VarChecker("@Default", "collection",
                "if($VAR$ == null) {\n" +
                        "    $VAR$ = Collections.emptyList();\n" +
                        "}"));

        varCheckers.add(new VarChecker("@Default", "map",
                "if($VAR$ == null) {\n" +
                        "    $VAR$ = Collections.emptyMap();\n" +
                        "}"));

        varCheckers.add(new VarChecker("@Default", "array; varags",
                "if($VAR$ == null) {\n" +
                        "    $VAR$ = new $VAR_TYPE$[0];\n" +
                        "}"));

        //Size / Length
        varCheckers.add(new VarChecker("@Size", "collection; map",
                "if($VAR$.size() <= $A_Size_P_min$ ||$VAR$.size() >= $A_Size_P_max$) {\n" +
                        "   throw new IllegalArgumentException(\"$VAR$ size must be between " +
                        "$A_Size_P_min$ and $A_Size_P_max$ (inclusive)\");\n" +
                        "}"));

        varCheckers.add(new VarChecker("@Size", "array; varags",
                "if($VAR$.length <= $A_Size_P_min$ ||$VAR$.length >= $A_Size_P_max$) {\n" +
                        "   throw new IllegalArgumentException(\"$VAR$ size must be between " +
                        "$A_Size_P_min$ and $A_Size_P_max$ (inclusive)\");\n" +
                        "}"));

        varCheckers.add(new VarChecker("@Size", "string",
                "if($VAR$.length() <= $A_Size_P_min$ ||$VAR$.length() >= $A_Size_P_max$) {\n" +
                        "throw new IllegalArgumentException(\"$VAR$ length must be between " +
                        "$A_Size_P_min$ and $A_Size_P_max$ (inclusive)\");\n" +
                        "}"));

        //Match
        varCheckers.add(new VarChecker("@Match", "String",
                "Pattern p = Pattern.compile($A_Match_P_value$);\n" +
                        "Matcher matcher = p.matcher($VAR$);\n" +
                        "if(matcher.matches() == false) {\n" +
                        "   throw new IllegalArgumentException(\"$VAR$ must match \" + $A_Match_P_value$);\n" +
                        "}"));

        //Numbers or string representation of numbers
        varCheckers.add(new VarChecker("@Max", "number",
                "if($VAR$ > $A_Max_P_value$) {\n" +
                        "   throw new IllegalArgumentException(\"$VAR$ value must be less or equals to $A_Max_P_value$ (inclusive)\");\n" +
                        "}  ",
                NUMBER_GRP));

        varCheckers.add(new VarChecker("@Min", "number",
                "if($VAR$ < $A_Min_P_value$) {\n" +
                        "   throw new IllegalArgumentException(\"$VAR$ value must be greater or equals to $A_Min_P_value$ (inclusive)\");\n" +
                        "}  ",
                NUMBER_GRP));


        varCheckers.add(new VarChecker("@MinMax", "number",
                "if($VAR$ < $A_MinMax_P_min$ ||$VAR$ > $A_MinMax_P_max$) {\n" +
                        "throw new IllegalArgumentException(\"$VAR$ value must be between " +
                        "$A_MinMax_P_min$ and $A_MinMax_P_max$ (inclusive)\");\n" +
                        "}  ", NUMBER_GRP));


        varCheckers.add(new VarChecker("@MinMax", "string",
                "try {\n" +
                        "   BigDecimal bd = new BigDecimal($VAR$);\n" +
                        "   if(bd.compareTo( BigDecimal.valueOf($A_MinMax_P_min$))<0 || bd.compareTo( BigDecimal.valueOf($A_MinMax_P_max$))>0) {\n" +
                        "       throw new IllegalArgumentException(\"$VAR$ size must be between $A_MinMax_P_min$ and $A_MinMax_P_max$ (inclusive)\");  \n" +
                        "   }\n" +
                        "} catch (NumberFormatException e) {\n" +
                        "   throw new IllegalArgumentException(\"$VAR$ must be numeric\", e);\n" +
                        "}", NUMBER_GRP));

        //String conversion / validation
        varCheckers.add(new VarChecker("@ToDate", "String",
                "Date date;\n" +
                        "try {\n" +
                        "   SimpleDateFormat sdf = new SimpleDateFormat($A_ToDate_P_value$);\n" +
                        "   date = sdf.parse($VAR$);\n" +
                        "} catch (ParseException e) {\n" +
                        "   throw new IllegalArgumentException(\"$VAR$ must be a date formatted as \" + $A_ToDate_P_value$, e);\n" +
                        "}", STRING_GRP));

        varCheckers.add(new VarChecker("@ToBoolean", "String",
                "boolean b = Boolean.parseBoolean($VAR$);", STRING_GRP));

        varCheckers.add(new VarChecker("@ToNumeric", "string",
                "BigDecimal bd;\n" +
                        "try {\n" +
                        "   bd = new BigDecimal($VAR$);\n" +
                        "} catch (NumberFormatException e) {\n" +
                        "   throw new IllegalArgumentException(\"$VAR$ must be numeric\", e);\n" +
                        "}", STRING_GRP));

        varCheckers.add(new VarChecker("@ToURL", "string",
                "URL url;\n" +
                        "try {\n" +
                        "   url = new URL($VAR$);\n" +
                        "} catch (MalformedURLException e) {\n" +
                        "   throw new IllegalArgumentException(\"$VAR$ must be a valid URL\", e);\n" +
                        "}", STRING_GRP));

        //misc
        varCheckers.add(new VarChecker("@Email", "string",
                "if(!EmailValidator.getInstance().isValid($VAR$)) {\n" +
                        "   throw new IllegalArgumentException(\"$VAR$ must be a valid email\");\n" +
                        "}", STRING_GRP));


        varCheckers.add(new VarChecker("@CreditCard", "string",
                "CreditCardValidator v = new CreditCardValidator();\n" +
                        "if(!v.isValid($VAR$)) {\n" +
                        "   throw new IllegalArgumentException(\"$VAR$ must be a valid credit card\");\n" +
                        "}", STRING_GRP));

        varCheckers.add(new VarChecker("@ISBN", "string",
                "if(!ISBNValidator.getInstance().isValidISBN10($VAR$)) {\n" +
                        "   throw new IllegalArgumentException(\"$VAR$ must be a valid ISBN\");\n" +
                        "}", STRING_GRP));

        //TODO Digits pattern

        //ContainsNoNull for collection, array, varags

        addHibernateLikeDefaultConfig();
        addJdk14DefaultConfig();
    }


    public boolean getAskToCreateSample() {
        return askToCreateSample;
    }

    public void setAskToCreateSample(boolean askToCreateSample) {
        this.askToCreateSample = askToCreateSample;
    }

    // --------------------- GETTER / SETTER METHODS ---------------------

    public List<VarChecker> getVarCheckers() {
        return varCheckers;
    }

    public void setVarCheckers(List<VarChecker> varCheckers) {
        this.varCheckers = varCheckers;
    }

}
